package com.example.forum.controller;

import com.example.forum.common.AppResult;
import com.example.forum.common.ResultCode;
import com.example.forum.config.AppConfig;
import com.example.forum.exception.ApplicationException;
import com.example.forum.model.User;
import com.example.forum.services.IUserService;
import com.example.forum.utils.MD5Util;
import com.example.forum.utils.StringUtil;
import com.example.forum.utils.UUIDUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * Created with IntelliJ IDEA.
 * Description: 用户 controller 层
 * User: DELL
 * Date: 2023-09-18
 * Time: 22:50
 */
@Api(tags = "用户接口")
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    /**
     * 用户注册
     *
     * @param username
     * @param nickname
     * @param password
     * @param passwordRepeat
     * @return
     */
    @ApiOperation("用户注册")
    @PostMapping("/register")
    public AppResult register(@ApiParam("用户名") @RequestParam("username") @NonNull String username,
                              @ApiParam("昵称") @RequestParam("nickname") @NonNull String nickname,
                              @ApiParam("密码") @RequestParam("password") @NonNull String password,
                              @ApiParam("确认密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat) {
        // 校验参数中均不能有空格
        if (StringUtil.hasSpace(username)) {
            return AppResult.fail("用户名中不能包含空格");
        }
        if (StringUtil.hasSpace(nickname)) {
            return AppResult.fail("昵称中不能包含空格");
        }
        if (StringUtil.hasSpace(password)) {
            return AppResult.fail("密码中不能包含空格");
        }
        // 1.校验密码和确认密码是否相同
        if (!password.equals(passwordRepeat)) {
            // 打印日志
            log.info(ResultCode.FAILED_TWO_PWD_NOT_SAME.toString());
            // 返回错误信息
            return AppResult.fail(ResultCode.FAILED_TWO_PWD_NOT_SAME);
        }
        // 2.基本信息赋值
        User user = new User();
        user.setUsername(username);
        user.setNickname(nickname);
        // 3.加密密码
        String salt = UUIDUtil.UUID_32();
        String ciphertext = MD5Util.md5(password, salt);
        // 4.盐值和密码赋值
        user.setSalt(salt);
        user.setPassword(ciphertext);
        // 5.调用 service 层
        userService.createNormalUser(user);
        // 6.返回数据
        return AppResult.success("注册成功");
    }

    /**
     * 用户登录
     *
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @ApiOperation("用户登录")
    @PostMapping("/login")
    public AppResult login(HttpServletRequest request,
                           @ApiParam("用户名") @RequestParam("username") @NonNull String username,
                           @ApiParam("密码") @RequestParam("password") @NonNull String password) {
        // 1.调用 service 层的 login()
        User user = userService.login(username, password);
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString() + ". username = " + username + ".");
            // 抛出异常
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_LOGIN));
        }
        // 2.获取 session
        HttpSession session = request.getSession(true);
        // 3.将用户信息存入 session 中
        session.setAttribute(AppConfig.USER_SESSION_KEY, user);
        // 4.返回结果
        return AppResult.success("登录成功");
    }

    /**
     * 获取用户信息
     *
     * @param id 用户 id
     * @return 若未传用户 id: 返回当前登录用户信息 <br>
     * 若传入用户 id: 返回对应的用户的信息
     */
    @ApiOperation("获取用户信息")
    @GetMapping("/info")
    public AppResult getUserInfo(HttpServletRequest request,
                                 @ApiParam("用户id") @RequestParam(name = "id", required = false) Long id) {
        User user = null;
        if (id == null) {
            // 1.如果用户 id 为 null,则从当前 session 中获取用户信息
            HttpSession session = request.getSession(false);
            user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
        } else {
            // 2.如果用户 id 不为 null,则返回对应用户的信息
            user = userService.selectById(id);
            if (user == null) {
                // 打印日志
                log.warn("非法查询用户信息,id = " + id + ".");
                // 返回信息
                return AppResult.fail(ResultCode.FAILED_USER_NOT_EXISTS);
            }
        }
        // 3.返回结果
        return AppResult.success(user);
    }

    /**
     * 退出登录
     *
     * @return
     */
    @ApiOperation("退出登录")
    @GetMapping("/logout")
    public AppResult logout(HttpServletRequest request) {
        // 获取 session
        HttpSession session = request.getSession(false);
        // 删除 session 信息
        if (session != null) {
            // 打印日志
            log.info("退出登录");
            session.invalidate();
        }
        // 返回结果
        return AppResult.success("退出成功");
    }

    /**
     * 修改个⼈信息
     *
     * @param username ⽤⼾名
     * @param nickname 昵称
     * @param gender   性别
     * @param email    邮箱
     * @param phoneNum 电话号
     * @param remark   个⼈简介
     * @return AppResult
     */
    @ApiOperation("修改个⼈信息")
    @PostMapping("/modifyInfo")
    public AppResult modifyInfo(HttpServletRequest request,
                                @ApiParam("⽤⼾名") @RequestParam(value = "username", required = false) String username,
                                @ApiParam("昵称") @RequestParam(value = "nickname", required = false) String nickname,
                                @ApiParam("性别") @RequestParam(value = "gender", required = false) Byte gender,
                                @ApiParam("邮箱") @RequestParam(value = "email", required = false) String email,
                                @ApiParam("电话号") @RequestParam(value = "phoneNum", required = false) String phoneNum,
                                @ApiParam("个⼈简介") @RequestParam(value = "remark", required = false) String remark) {
        // 检验参数是否全部为空
        if (StringUtil.isEmpty(username) && StringUtil.isEmpty(nickname)
                && gender == null && StringUtil.isEmpty(email)
                && StringUtil.isEmpty(phoneNum) && StringUtil.isEmpty(remark)) {
            // 打印日志
            log.warn("检测到非法访问 -- 修改个人信息时不传入任何参数");
            // 返回结果
            return AppResult.fail(ResultCode.FAILED);
        }
        // username,nickname,email,phoneNum,remark均不能包含空格
        if ((!StringUtil.isEmpty(username) && StringUtil.hasSpace(username))
                || (!StringUtil.isEmpty(nickname) && StringUtil.hasSpace(nickname))
                || (!StringUtil.isEmpty(email) && StringUtil.hasSpace(email))
                || (!StringUtil.isEmpty(phoneNum) && StringUtil.hasSpace(phoneNum))
                || (!StringUtil.isEmpty(remark) && StringUtil.hasSpace(remark))) {
            // 打印日志
            log.warn("用户修改个人信息时,传入的信息中包含空格");
            // 返回结果
            return AppResult.fail(ResultCode.FAILED_HAS_SPACE);
        }
        // 检测 gender 的合法性
        if (gender != null && (gender < 0 || gender > 2)) {
            // 打印日志
            log.warn("检测到非法访问 -- 修改个人信息时传入的性别异常,gender = " + gender);
            // 返回结果
            return AppResult.fail(ResultCode.FAILED);
        }
        // 从session中获取当前登录对象
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
        // 构造更新对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setUsername(username);
        updateUser.setNickname(nickname);
        updateUser.setGender(gender);
        updateUser.setEmail(email);
        updateUser.setPhoneNum(phoneNum);
        updateUser.setRemark(remark);
        // 调用 service,更新
        userService.update(updateUser);
        // 查询最新的⽤⼾信息
        user = userService.selectById(user.getId());
        // 把最新的⽤⼾信息设置到session中
        session.setAttribute(AppConfig.USER_SESSION_KEY, user);
        // 打印日志
        log.info("用户修改个人信息," + updateUser);
        return AppResult.success(user);
    }

    /**
     * 修改密码
     *
     * @param oldPassword    原密码
     * @param newPassword    新密码
     * @param passwordRepeat 确认密码
     * @return
     */
    @ApiOperation("修改密码")
    @PostMapping("/modifyPwd")
    public AppResult modifyPassword(HttpServletRequest request,
                                    @ApiParam("原密码") @RequestParam("oldPassword") @NonNull String oldPassword,
                                    @ApiParam("新密码") @RequestParam("newPassword") @NonNull String newPassword,
                                    @ApiParam("确认密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat) {
        // 参数校验
        if (StringUtil.hasSpace(newPassword)) {
            // 打印日志
            log.warn("检测到用户修改密码时,传入的新密码中包含空格");
            // 返回结果
            return AppResult.fail(ResultCode.FAILED_HAS_SPACE);
        }
        if (!newPassword.equals(passwordRepeat)) {
            // 打印日志
            log.warn("检测到非法访问 -- 修改用户密码时提供的新密码和重复密码不一致");
            // 返回结果
            return AppResult.fail(ResultCode.FAILED);
        }
        // 从session中获取用户id
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
        // 根据用户 id 查询用户信息
        User selectUser = userService.selectById(user.getId());
        if (selectUser == null) {
            // 打印日志
            log.warn("检测到非法访问 -- 修改用户密码时根据session中的用户id查询不到用户信息");
            // 返回结果
            return AppResult.fail(ResultCode.FAILED);
        }
        // 验证 oldPassword 是否正确
        String salt = selectUser.getSalt();
        String ciphertext = MD5Util.md5(oldPassword, salt);
        if (!ciphertext.equals(selectUser.getPassword())) {
            // 打印日志
            log.warn("修改密码时,提供的旧密码不正确,user id = " + user.getId() + ", oldPassword = " + oldPassword);
            // 返回结果
            return AppResult.fail(ResultCode.FAILED_PASSWORD);
        }
        // 生成更新对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        String newCiphertext = MD5Util.md5(newPassword, salt);
        updateUser.setPassword(newCiphertext);
        // 调用 service 层,更新
        userService.update(updateUser);
        // 打印日志
        log.info("用户修改密码,user id = " + user.getId() + ",oldPassword = "
                + oldPassword + ",newPassword = " + newPassword);
        // 强制让session失效,使得前端跳转到登录页面,重新登陆
        session.invalidate();
        // 返回结果
        return AppResult.success();
    }

    /**
     * 上传头像
     *
     * @param file 头像文件
     * @return
     */
    @ApiOperation("上传头像")
    @PostMapping("/upload")
    public AppResult upload(HttpServletRequest request,
                            @ApiParam("上传的头像") @RequestPart("file") @NonNull MultipartFile file) {
        // 校验文件是否为空
        if (file.isEmpty()) {
            // 打印日志
            log.warn("检测到用户上传的头像为空");
            // 返回结果
            return AppResult.fail(ResultCode.FAILED_AVATAR_IS_EMPTY);
        }
        // 从 session 中获取用户 id
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
        // 调用 service 层,更新
        String filePath = userService.uploadAvatar(user.getId(), file);
        // 更新 session 中的 user 信息
        user.setAvatarUrl(filePath);
        session.setAttribute(AppConfig.USER_SESSION_KEY, user);
        // 返回结果
        return AppResult.success(filePath);
    }

}
